﻿using Lib.ConfigurationBase;
using Lib.Data.Entitys;
using Lib.Data.Enumeration;
using Microsoft.Extensions.Configuration;

namespace Lib.Data; 
/// <summary>
/// 数据库的工厂
/// </summary>
public static class DatabaseFactory {
    /// <summary>
    /// 数据库连接 ConnectionStrings 配置实体类
    /// </summary>
    public static Connection Connection { get; set; }
    /// <summary>
    /// 
    /// </summary>
    public static IConfigurationRoot ConfigurationRoot { get; set; }
    /// <summary>
    /// 默认数据库连接名称
    /// </summary>
    public static string ConnectName { get; private set; }
    /// <summary>
    /// 构造函数
    /// </summary>
    static DatabaseFactory() {
        //
        Connection = ConfigsBase.Initialize<Connection>("@ConnectionStrings", null, (Root, File, Key, Reload) => {
            ConfigurationRoot = Root;
        });
        //
        ConnectName = Connection.ConnectKey;
        //
        if (string.IsNullOrEmpty(ConnectName)) {
            ConnectName = "Connection";
        }
    }
    /// <summary>
    /// 获取数据库操作通用类（模式：数据库连接配置对象）
    /// </summary>
    public static DataBase Create(Connect e) {
        if (e == null) {
            throw new ArgumentNullException(nameof(e), "数据库连接配置对象不能为空！");
        }
        if (string.IsNullOrEmpty(e.Key)) {
            throw new ArgumentNullException(nameof(e), "请设置数据库连接关键字！");
        }
        if (Connection.ConnectionStrings.TryGetValue(e.Key, out Connect Value)) {
            e = Value;
        }
        if (e.Active) {
        
        } else {
            Initialize(e);
        }
        return Init(e);
    }
    /// <summary>
    /// 获取数据库操作通用类（模式：数据库连接关键字）
    /// </summary>
    public static DataBase Create(string ConnectionName = null) {
        if (string.IsNullOrEmpty(ConnectionName)) {
            ConnectionName = ConnectName;
        }
        Connect e = null;
        if (Connection.ConnectionStrings.TryGetValue(ConnectionName, out Connect Value)) {
            e = Value;
        }
        if (e == null) {
            throw new ArgumentNullException(nameof(ConnectionName), "连接数据库出错,请在配置文件中检查相关配置项");
        }
        if (e.Active) {

        } else {
            Initialize(e);
        }
        return Init(e);
    }
    /// <summary>
    /// 获取数据库操作通用类（模式：数据库连接字符串）
    /// </summary>
    public static DataBase Create(string ConnectString, dbType dbType) {
        var Key = dbType.ConnectKey(ConnectString);
        var e = Initialize(Key, dbType, ConnectString);
        if (!e.Active) {
            Initialize(e);
        } 
        return Init(e, ConnectString);
    }
    /// <summary>
    /// 
    /// </summary>
    private static DataBase Init(Connect e, string ConnectString = null) {
        var db = DataBase.Create();
        db.Key = e.Key;
        db.dbType = e.dbType;
        db.ProviderName = e.Provider;
        if (e.ConnectType == ConnectType.File) {
            db.Initialize(ConnectString);
        } else {
            db.ConnectionString = e.ConnectionString;
        }
        db.PagingKey = e.PagingKey;
        db.ParameterChar = e.ParameterChar;
        db.LogEnable = e.LogEnable.Value;
        db.IsDevelopment = e.IsDevelopment.Value;
        db.RecordTime = e.RecordTime;
        db.LogKey = e.LogKey;
        db.ConnectionStatus = e.ConnectionStatus;
        db.Init();
        return db;
    }
    /// <summary>
    /// 初始化连接对象属性默认值
    /// </summary>
    private static void Initialize(Connect e) {
        if (string.IsNullOrEmpty(e.ParameterChar)) {
            if (e.dbType == dbType.Oracle) {
                e.ParameterChar = ":";
            } else {
                e.ParameterChar = "@";
            }
        }
        if(e.ConnectType == ConnectType.Key) {
            if (string.IsNullOrEmpty(e.ConnectionString)) {
                InitConnectionString(e);
            }
        } 
        e.LogEnable ??= true;
        e.IsDevelopment ??= true;
        if (string.IsNullOrEmpty(e.LogKey)) {
            e.LogKey = $"{e.Key}.SQL";
        }
        if (Connection.SQLs.TryGetValue(e.dbType.ToString(),out Pagination P)) {
            if (string.IsNullOrEmpty(e.PagingKey)|| !P.SQLs.ContainsKey(e.PagingKey)) {
                e.PagingKey = P.Key;
            } 
        } else {
            e.PagingKey = null;
        }
        if (string.IsNullOrEmpty(e.PagingKey)) {
            e.PagingKey = "Common";
        }
        e.Active = true;
    }
    /// <summary>
    /// 初始化数据库连接字符串方式（ ConnectType.ConnectionStrings、ConnectType.File ）
    /// </summary>
    private static Connect Initialize(string Key, dbType dbType, string ConnectString) {
        var e = Connect.Create(Key);
        e.dbType = dbType;
         switch (e.dbType) {
            case dbType.Excel:
            case dbType.Access:
            case dbType.Text:
                e.ConnectionStatus = ConnectionStatus.CloseOnExit;
                e.ConnectType = ConnectType.File;
                if (Connection.Providers.ContainsKey("OLEDB")) {
                    e.Provider = dbType.OLEDB.ToString();
                } else {
                    e.Provider = dbType.ODBC.ToString();
                }
                break;
            default:
                e.ConnectionStatus = ConnectionStatus.None;
                e.ConnectType = ConnectType.ConnectionStrings;
                if (e.dbType == dbType.UnClaim) {
                    e.dbType = dbType.MSSQL;
                }
                e.Provider = e.dbType.ToString();
                e.ConnectionString = ConnectString;
                break;
        }
        if (Connection.ConnectionStrings.TryAdd(Key, e)) {
          
        }
        return e;
    }
    /// <summary>
    /// 生成文件路径数据库连接字符串
    /// </summary>
    private static void Initialize(this DataBase db, string Path) {
        db.LogKey = $"{Path.Replace(@"\", "/").Replace("/", ".").Replace(":", "")}.SQL";
        if (Connection.ConnectiveStrings.TryGetValue(db.dbType.ToString(), out Dictionary<string, string> e)) {
            if (e.TryGetValue(db.ProviderName, out string Connect)) {
                db.ConnectionString = Connect
                    .Replace("{DataBase}", Path)
                    .Replace("{UID}", null)
                    .Replace("{Password}", null)
                    .Replace("{Parameters}", null);
            }
        }
    }
    /// <summary>
    /// 生成数据库连接字符串（模式：数据库连接关键字）
    /// </summary>
    private static void InitConnectionString(Connect e) {
        if (Connection.ConnectiveStrings.TryGetValue(e.dbType.ToString(), out Dictionary<string, string> P)) {
            if (P.TryGetValue(e.Provider, out string Connect)) {
                switch (e.dbType) {
                    case dbType.MSSQL:
                        e.ConnectionString = Connect
                            .Replace("{Server}", e.Server)
                            .Replace("{Port}", (e.Port > 0 ? $"{e.Port}" : ""))
                            .Replace("{DataBase}", e.DataBase)
                            .Replace("{UID}", e.UID)
                            .Replace("{Password}", e.Password)
                            .Replace("{Parameters}", e.Parameters);
                        break;
                    case dbType.MySQL:
                        e.ConnectionString = Connect
                            .Replace("{Server}", e.Server)
                            .Replace("{Port}", (e.Port > 0 ? e.Port : 3306).ToString())
                            .Replace("{DataBase}", e.DataBase)
                            .Replace("{UID}", e.UID)
                            .Replace("{Password}", e.Password)
                            .Replace("{Parameters}", e.Parameters);
                        break;
                    case dbType.PostgreSQL:
                        e.ConnectionString = Connect
                            .Replace("{Server}", e.Server)
                            .Replace("{Port}", (e.Port > 0 ? e.Port : 5432).ToString())
                            .Replace("{DataBase}", e.DataBase)
                            .Replace("{UID}", e.UID)
                            .Replace("{Password}", e.Password)
                            .Replace("{Parameters}", e.Parameters);
                        break;
                    case dbType.Oracle:
                        e.ConnectionString = Connect
                            .Replace("{Server}", e.Server)
                            .Replace("{Port}", (e.Port > 0 ? e.Port : 1521).ToString())
                            .Replace("{DataBase}", e.DataBase)
                            .Replace("{UID}", e.UID)
                            .Replace("{Password}", e.Password)
                            .Replace("{Parameters}", e.Parameters);
                        break;
                    case dbType.MariaDB:
                        e.ConnectionString = Connect
                            .Replace("{Server}", e.Server)
                            .Replace("{Port}", (e.Port > 0 ? e.Port : 3306).ToString())
                            .Replace("{DataBase}", e.DataBase)
                            .Replace("{UID}", e.UID)
                            .Replace("{Password}", e.Password)
                            .Replace("{Parameters}", e.Parameters);
                        break;
                    case dbType.SQLite:
                    case dbType.Access:
                    case dbType.Excel:
                    case dbType.Text:
                        e.ConnectionString = Connect
                            .Replace("{DataBase}", e.DataBase)
                            .Replace("{UID}", e.UID)
                            .Replace("{Password}", e.Password)
                            .Replace("{Parameters}", e.Parameters);
                        break;
                    default:
                        break;
                }
            }
        }
    }

}
